#! /usr/bin/perl 

use strict;

use CGI;
use CGI::Carp qw/fatalsToBrowser/;
use Template;
use JSON;
use Data::Dumper;

my $script = "/home/avi/wordpress_html/tlscheck/analyze-ssl.pl";
my $cgi = CGI->new();
my $tt = Template->new(
	INCLUDE_PATH => "/home/avi/wordpress_html/tlscheck/templates/",
	INTERPOLATE => 1,
);

print "Content-type: text/html\n\n";

if(!$cgi->param('host')){
	$tt->process('main');
	exit;
}

my $form_values = {
	port => $cgi->param('port'),
	host => $cgi->param('host'),
	sni_name => $cgi->param('sni_name'),
};

my $host = $cgi->param('host');
$host =~ s#^https?://##;
$host =~ s#/$##;
$host =~ s/\s+//g;

my $port;
# If the port is given as a param, then that is the one to use
my $port = $1 if ($cgi->param('port') =~ m/^(\d+)$/);

# But even if it's given as a param, we need to strip it from the host param:
if($host =~ m/^(\S+):(\d+)/){
	$host = $1;
	$port = $2 unless $port > 0;
}
$port = '443' unless $port > 0;
$port =~ s/\s+//g;

my $sni_name = $cgi->param('sni_name');
my $starttls = $cgi->param('starttls') or undef;
my $debug = $cgi->param('debug');
$sni_name =~ s/\s+//g;

my @errors;
if(!$port or $port !~ m/^\d+$/){
	push(@errors, "Invalid port number: '$port'");
}
if($host !~ m/^[\w\d-\.]+$/){
	push(@errors, "Invalid host: '$host'");
}
if($sni_name =~ m/.+/ and $sni_name !~ m/^[\w\d-\.]+$/){
	push(@errors, "Invalid SNI hostname: '$sni_name'");
}

if($starttls && $starttls !~ m/^(imap|smtp|http_upgrade|http_proxy|pop|ftp|postgresql)$/){
	push(@errors, "Invalid StartTLS protocol '$starttls'");
}

if($debug and ! ($ENV{REMOTE_ADDR} eq '80.87.128.222') ){
	push(@errors, $ENV{REMOTE_ADDR}." is not allowed to debug this");
}

if($errors[0]){
	$tt->process('main', {errors => \@errors, form_values => $form_values});
	exit;
}


my $cmd = $script;
$cmd.= " --name $sni_name" if $sni_name;
$cmd.= " --starttls $starttls" if $starttls;
$cmd.= " $host:$port";

my $json = `$cmd`;

my $results;
eval {$results = decode_json($json); };
if($@){
	if($debug){
		print "Content-type: text/plain\n\n";
		print "Host: $host\nPort:$port\nSNI:$sni_name\nStartTLS:$starttls\ncmd:$cmd\n\n\n\n";
		print $json;
		exit;
	}
	push(@errors, "Failed to connect to $host:$port");
	push(@errors, "Tried to use $starttls StartTLS") if $starttls;
	$tt->process('main', {errors => \@errors});
	exit;
}
my @summary;

if($starttls){
	push(@summary, "Used IMAP STARTTLS");
}

# Herein we're interested in the host by name, not address:
$host = $sni_name if $sni_name =~ m/.+/;

if($results->{cert_chain}->[0]->{subject_alt_name}){
	my @alt_names = @{$results->{cert_chain}->[0]->{subject_alt_name}};
	if(grep(m/^$host$/,  @alt_names) > 0 ){
		push(@summary, "Name is listed on certificate ($host)");
	}else{
		push(@summary, "Name is NOT listed on certificate ($host)");
	}
}

my $days_until_expiry = int(($results->{cert_chain}->[0]->{not_after_epoch} - time())/(24*60*60));
push(@summary, "Certificate expires in $days_until_expiry days ($results->{cert_chain}->[0]->{not_after_cdate})");

$tt->process('main', {results => $results, json => $json, form_values => $form_values, summary => \@summary, host => $host, port => $port});
